/**
 * 
 */
package ac.svn.accesscontrol.controller;

import java.util.HashSet;
import java.util.Set;

import ac.notification.event.INotificationListener;
import ac.notification.event.NotificationEvent;
import ac.notification.manager.NotificationRegistrar;
import ac.svn.accesscontrol.manager.SVNInfoManager;
import ac.svn.accesscontrol.store.AccessUnit;
import ac.svn.accesscontrol.store.ISVNIdentifier;
import ac.svn.accesscontrol.store.ISVNItem;
import ac.svn.accesscontrol.store.SVNGroup;
import ac.svn.accesscontrol.store.SVNLocation;
import ac.svn.accesscontrol.store.SVNUser;
import ac.svn.accesscontrol.ui.IUIConstants;
import ac.svn.accesscontrol.utils.Utility;

/**
 * @author Ankush Chaudhary
 *
 */
public class EntityDeletionHandler implements INotificationListener,
ISVNIdentifier 
{




	public EntityDeletionHandler() {
		super();
		NotificationRegistrar.registerListener(this);
	}

	@Override
	public Set<String> declaredSubscriptionSet() 
	{
		Set<String> subscriptions = new HashSet<String>();
		subscriptions.add(CMD_DELETE_ENTITY);
		return subscriptions;
	}

	@Override
	public void receiveEvent(NotificationEvent notificationEvent) 
	{
		final String neId = notificationEvent.getPropertyIdentifier();
		if(neId.contains(CMD_DELETE_ENTITY))
		{
			deleteEntityHandler(notificationEvent);
		}
	}

	private void deleteEntityHandler(NotificationEvent notificationEvent) 
	{
		//Get the target entity to be deleted.
		ISVNItem item = (ISVNItem) notificationEvent.getPropertyValue();

		//Check if event is sent correctly.
		if(null != item)
		{
			//Check if entity is a SVNUser.
			if(item instanceof SVNUser)
			{
				SVNUser svnUser = (SVNUser) item;
				deleteUser(svnUser);
			}

			//If entity is a SVN Group.
			else if(item instanceof SVNGroup)
			{
				SVNGroup group = (SVNGroup) item;
				deleteGroup(group);
			}

			//If entity is a SVN Location.
			else if(item instanceof SVNLocation)
			{
				SVNLocation location = (SVNLocation) item;
				deleteLocation(location);
			}

			//If entity is an Access Unit.
			else if(item instanceof AccessUnit)
			{

			}
		}
	}

	private void deleteLocation(SVNLocation location) 
	{
		SVNInfoManager svnInfoMgr = SVNInfoManager.getInfoManager();

		//Deleting a location involves simply removing SVNLocation object from SVNInformation Manager
		//as not other object contains reference to SVNLocation. All AccessUnits attached to are removed from
		//selected SVN location and also removed from SVNInformation Manager.

		//Keep reference to access units before removing SVNLocation.
		Set<String> accessUnitIds = new HashSet<String>(location.getAccessUnits());

		//Delete SVNLocaiton from SVNInformation Manager.
		svnInfoMgr.removeLocation(location.getId());
		
		//Once Location is delete from SVN Information Manager, remove associated Access Units.
		for(String accessUnitId : accessUnitIds)
		{
			svnInfoMgr.removeAccessUnit(accessUnitId);
		}
		
		

		//Notify system of location removal
		Utility.sendNotification(N_LOCATION_REMOVED);

		//Notify System to Update UI containing Location.
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_LOCATION);

	}

	private void deleteGroup(SVNGroup group) 
	{
		SVNInfoManager svnInfoMgr = SVNInfoManager.getInfoManager();

		//Deleting a location is bit tricky as User and AccessUnits contain reference to a Group.
		//To delete a group we need to find out dependent entities.

		//Get List of user who are member of this group.
		Set<String> members = group.getGroupMembers();

		//Get all users one by one and remove group membership from their membership.
		for(String userId : members)
		{
			//Get user from store and update membership.
			SVNUser user = svnInfoMgr.getSvnUser(userId);
			user.getGroups().remove(group.getId());

			//Update user back to store.
			svnInfoMgr.updateUser(user);
		}

		//Get all location in which group has been assigned permissions.
		Set<ISVNItem> allAccessUnits = svnInfoMgr.getAllAccessUnit(group.getId());

		for(ISVNItem item : allAccessUnits)
		{
			AccessUnit accessUnit = (AccessUnit) item;

			//Get list of location in which group has been assigned access.
			SVNLocation location = svnInfoMgr.getLocation(accessUnit.getLocationPath());

			//Remove reference of access unit from Location
			location.getAccessUnits().remove(accessUnit.getAccessUnitId());

			//Update location back to store.
			svnInfoMgr.updateLocation(location);

			//Remove access unit from store.
			svnInfoMgr.removeAccessUnit(accessUnit.getId());
		}


		//Remove Group itself.
		svnInfoMgr.removeGroup(group.getId());

		//Notify system and listings to update
		Utility.sendNotification(N_GROUP_REMOVED);

		//Notify System to Update UI containing Location.
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_GROUP);
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_LOCATION);
	}

	private void deleteUser(SVNUser svnUser) 
	{
		SVNInfoManager svnInfoMgr = SVNInfoManager.getInfoManager();

		// Deleting user is same as deleting Group. while deleting a user,
		// references from Group and Access Units have to be removed.

		for(String groupId : svnUser.getGroups())
		{
			//Get actual from svn
			SVNGroup group = svnInfoMgr.getGroup(groupId);

			//Remove subscription of user.
			group.getGroupMembers().remove(svnUser.getId());

			//Update group back to store.
			svnInfoMgr.updateGroup(group);
			
		}

		//Get list of access units which are for user.
		Set<ISVNItem> accessUnits = svnInfoMgr.getAllAccessUnit(svnUser.getId());

		for(ISVNItem item : accessUnits)
		{
			AccessUnit accessUnit = (AccessUnit) item;

			//Get list of location in which group has been assigned access.
			SVNLocation location = svnInfoMgr.getLocation(accessUnit.getLocationPath());

			//Remove reference of access unit from Location
			location.getAccessUnits().remove(accessUnit.getAccessUnitId());

			//Update location back to store.
			svnInfoMgr.updateLocation(location);

			//Remove access unit from store.
			svnInfoMgr.removeAccessUnit(accessUnit.getId());
		}

		//Remove user from store.
		svnInfoMgr.removeUser(svnUser.getId());

		//Notify system and listings to update
		Utility.sendNotification(N_USER_REMOVED);

		//Notify System to Update UI containing Location.
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_USER);
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_GROUP);
		Utility.sendNotification(N_UPDATE_LISTINGS,IUIConstants.C_LIST_TYPE_LOCATION);
	}




}
